package beanstao.util.collections;

import java.util.ArrayList;

import net.sf.json.JSONObject;

import beanstao.util.Util;

public class LinkedIntArray
{

	public LinkedIntArray()
	{
		this(256);
	}

	public LinkedIntArray(int size)
	{
		if (size < 0)
		{
			Util.makeThrow("width must >0!");
		}
		this.width = size;
		this.cache = new ArrayList<int[]>();
	}

	private int offset;
	private int cursor;
	private final int width;
	private final ArrayList<int[]> cache;

	public LinkedIntArray push(int e)
	{
		int[] array;
		int row = this.cursor / this.width;
		int i = this.cursor % this.width;
		if ((this.cache.size() == 0) || ((this.cursor != this.offset) && (i == 0)))
		{
			array = new int[this.width];
			this.cache.add(array);
		}
		else
		{
			array = this.cache.get(row);
		}
		array[i] = e;
		this.cursor++;
		return this;
	}

	public int popFirst()
	{
		return this.innerGet(this.offset++);
	}

	public int popLast()
	{
		return this.innerGet(--this.cursor);
	}

	public LinkedIntArray popLast(int num)
	{
		for (int i = 0; i < num; i++)
		{
			this.popLast();
		}
		return this;
	}

	public int first()
	{
		if (this.size() == 0)
		{
			return (char) 0;
		}
		return this.innerGet(this.offset);
	}

	public int last()
	{
		if (this.size() == 0)
		{
			return (char) 0;
		}
		return this.innerGet(this.cursor - 1);
	}

	public LinkedIntArray set(int index, int e)
	{
		this.checkBound(index);
		index += this.offset;
		int[] array = this.cache.get(index / this.width);
		array[index % this.width] = e;
		return this;
	}

	private void checkBound(int index)
	{
		if ((index >= this.size()) || (index < 0))
		{
			throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + this.size());
		}
	}

	public LinkedIntArray clear()
	{
		this.cache.clear();
		this.cursor = 0;
		this.offset = 0;
		return this;
	}

	private int innerGet(int index)
	{
		int[] array = this.cache.get(index / this.width);
		return array[index % this.width];
	}

	public int get(int index)
	{
		this.checkBound(index);
		return this.innerGet(index + this.offset);
	}

	public boolean isEmpty()
	{
		return 0 == this.cursor - this.offset;
	}

	public int size()
	{
		return this.cursor - this.offset;
	}

	public int[] toArray()
	{
		int[] re = new int[this.size()];
		for (int i = 0; i < re.length; i++)
		{
			re[i] = (char) this.get(i);
		}
		return re;
	}

	@Override
	public String toString()
	{
		return Util.concat(',', this.toArray()).toString();
	}

	public String toJson()
	{
		return JSONObject.fromObject(this.toArray()).toString();
	}
}
